package net.simflow.swf.analyzer.gui;

import java.awt.Color;
import java.awt.Frame;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;

import net.simflow.swf.analyzer.bggraph.data.BGGraphPkg;
import net.simflow.swf.analyzer.bggraph.opt.BGGraphMaker;
import net.simflow.swf.analyzer.bggraph.opt.BGNodeToLabelTransformer;
import net.simflow.swf.analyzer.bggraph.opt.BGNodeToPaintTransformer;
import net.simflow.swf.analyzer.bggraph.opt.BGVisualizationServerBuilder;
import net.simflow.swf.analyzer.bgnetwork.data.BGLink;
import net.simflow.swf.analyzer.bgnetwork.data.BGNetwork;
import net.simflow.swf.analyzer.bgnetwork.data.BGNode;
import net.simflow.swf.analyzer.bgnetwork.stats.data.BGNetworkStats;
import net.simflow.swf.analyzer.chart.BGNetworkStatsChart;
import net.simflow.swf.analyzer.chart.ExecStatsChart;
import net.simflow.swf.analyzer.chart.NetworkStatsChart;
import net.simflow.swf.analyzer.data.DataPkg;
import net.simflow.swf.analyzer.data.StringConstant;
import net.simflow.swf.analyzer.data.TupleStrInt;
import net.simflow.swf.analyzer.exec.data.ExecParameterPkg;
import net.simflow.swf.analyzer.exec.data.ExecResult;
import net.simflow.swf.analyzer.exec.data.ExecResultPkg;
import net.simflow.swf.analyzer.exec.data.TaskExecResult;
import net.simflow.swf.analyzer.exec.opt.Executor;
import net.simflow.swf.analyzer.exec.stats.data.ExecStats;
import net.simflow.swf.analyzer.exec.stats.opt.ExecStatsAnalyzer;
import net.simflow.swf.analyzer.fileprinter.BGNetworkStatsFilePrinter;
import net.simflow.swf.analyzer.fileprinter.ExecResultFilePrinter;
import net.simflow.swf.analyzer.fileprinter.ExecStatsFilePrinter;
import net.simflow.swf.analyzer.fileprinter.FilePrinter;
import net.simflow.swf.analyzer.fileprinter.GraphStatsFilePrinter;
import net.simflow.swf.analyzer.fileprinter.NetworkStatsFilePrinter;
import net.simflow.swf.analyzer.graph.data.GraphPkg;
import net.simflow.swf.analyzer.graph.opt.EdgeToStrokeTransformer;
import net.simflow.swf.analyzer.graph.opt.GraphMaker;
import net.simflow.swf.analyzer.graph.opt.NodeToLabelTransformer;
import net.simflow.swf.analyzer.graph.opt.NodeToPaintTransformer;
import net.simflow.swf.analyzer.graph.opt.VisualizationServerBuilder;
import net.simflow.swf.analyzer.graph.stats.data.GraphStats;
import net.simflow.swf.analyzer.graph.stats.opt.GraphStatsAnalyzer;
import net.simflow.swf.analyzer.gui.exec.para.ExecParameterSettingDialog;
import net.simflow.swf.analyzer.gui.ginfo.display.GraphInfoDisplayConfigDialog;
import net.simflow.swf.analyzer.gui.ginfo.generator.BGGenerator;
import net.simflow.swf.analyzer.gui.ginfo.generator.BGOneGenerator;
import net.simflow.swf.analyzer.gui.ginfo.generator.DegreeGenerator;
import net.simflow.swf.analyzer.gui.ginfo.generator.ExecGenerator;
import net.simflow.swf.analyzer.gui.ginfo.generator.IOGenerator;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Link;
import net.simflow.swf.analyzer.network.data.Network;
import net.simflow.swf.analyzer.network.data.NetworkPkg;
import net.simflow.swf.analyzer.network.data.Node;
import net.simflow.swf.analyzer.network.data.Service;
import net.simflow.swf.analyzer.network.stats.data.NetworkStats;
import net.simflow.swf.analyzer.opt.CusListener;
import net.simflow.swf.analyzer.opt.FontDataClone;
import net.simflow.swf.analyzer.opt.SuccessThread;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.wb.swt.SWTResourceManager;

import edu.uci.ics.jung.graph.Graph;

public class NetworkAnalyzerGUI extends Shell {
	public static final int STYLE_WHOLE_NETWORK = 0;
	public static final int STYLE_SERVICE_NETWORK = 1;

	private static final String GRAPH_NODE_PAINT_STYLE_IO_STR = "IO";
	private static final String GRAPH_NODE_PAINT_STYLE_DEGREE_STR = "Degree Distribution";
	private static final String GRAPH_NODE_PAINT_STYLE_EXECUTION_STR = "Execution Result";
	private static final String[] GRAPH_NODE_PAINT_STYLE = {
			GRAPH_NODE_PAINT_STYLE_IO_STR, GRAPH_NODE_PAINT_STYLE_DEGREE_STR,
			GRAPH_NODE_PAINT_STYLE_EXECUTION_STR };
	private static final int GRAPH_NODE_PAINT_STYLE_IO_INT = 0;
	private static final int GRAPH_NODE_PAINT_STYLE_EXECUTION_INT = 2;

	private static final String GRAPH_NODE_LABEL_STYLE_BLANK_STR = "Blank";
	private static final String GRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR = "Short Name";
	private static final String GRAPH_NODE_LABEL_STYLE_NAME_STR = "Name";
	private static final String[] GRAPH_NODE_LABEL_STYLE = {
			GRAPH_NODE_LABEL_STYLE_BLANK_STR,
			GRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR,
			GRAPH_NODE_LABEL_STYLE_NAME_STR };
	private static final int GRAPH_NODE_LABEL_STYLE_SHORT_NAME_INT = 1;

	private static final String BGGRAPH_NODE_PAINT_STYLE_BG_STR = "Bipartite Graph";
	private static final String[] BGGRAPH_NODE_PAINT_STYLE = { BGGRAPH_NODE_PAINT_STYLE_BG_STR };
	private static final int BGGRAPH_NODE_PAINT_STYLE_BG_INT = 0;

	private static final String BGGRAPH_NODE_LABEL_STYLE_BLANK_STR = "Blank";
	private static final String BGGRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR = "Short Name";
	private static final String BGGRAPH_NODE_LABEL_STYLE_NAME_STR = "Name";
	private static final String[] BGGRAPH_NODE_LABEL_STYLE = {
			BGGRAPH_NODE_LABEL_STYLE_BLANK_STR,
			BGGRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR,
			BGGRAPH_NODE_LABEL_STYLE_NAME_STR };
	private static final int BGGRAPH_NODE_LABEL_STYLE_SHORT_NAME_INT = 1;

	private static final int GRAPH_NODE_UPPER_BOUND = 1000;
	private static final int GRAPH_LINK_UPPER_BOUND = 1000;

	private static final int GRAPH_STYLE_GRAPH = 0;
	private static final int GRAPH_STYLE_BG = 1;

	private ScienceWorkflowAnalyzer main;
	private String showTitle;
	private String fileTitle;

	private DataPkg dataPkg = null;
	private Flow flow = null;
	private BGNode bgNode = null;
	private GraphPkg graphPkg = null;
	private BGGraphPkg bgGraphPkg = null;

	private int graphStyle = GRAPH_STYLE_GRAPH;
	private String path;
	private LinkedHashMap<String, Boolean> ioDisplayConfig = IOGenerator
			.getInstance().getDefaultConfig();
	private LinkedHashMap<String, Boolean> degreeDisplayConfig = DegreeGenerator
			.getInstance().getDefaultConfig();
	private LinkedHashMap<String, Boolean> execDisplayConfigGraph = ExecGenerator
			.getInstance().getDefaultConfigGraph();
	private LinkedHashMap<String, Boolean> execDisplayConfigResult = ExecGenerator
			.getInstance().getDefaultConfigResult();
	private LinkedHashMap<String, Boolean> execDisplayConfigStats = ExecGenerator
			.getInstance().getDefaultConfigStats();
	private LinkedHashMap<String, Boolean> bgDisplayConfig = BGGenerator
			.getInstance().getDefaultConfigBG();
	private LinkedHashMap<String, Boolean> bgFlowDisplayConfig = BGGenerator
			.getInstance().getDefaultConfigFlow();
	private LinkedHashMap<String, Boolean> bgServiceDisplayConfig = BGGenerator
			.getInstance().getDefaultConfigService();

	private Composite cmpGraphContent;
	private Frame frmGraphContent;
	private StyledText txtOutput;
	private Combo cmbGraphPaintStyle;
	private Combo cmbNodeLabelStyle;
	private StyledText txtGraphInfo;
	private Label lblOutput;
	private Label lblGraphTitle;
	private MenuItem mntmDrawAcnode;
	private SashForm sashGraphDisplay;

	/**
	 * Create the shell.
	 * 
	 * @param display
	 */
	public NetworkAnalyzerGUI(final Display display,
			ScienceWorkflowAnalyzer mainApp, int style) {
		super(display, SWT.SHELL_TRIM);

		this.main = mainApp;
		this.main.getClass();
		switch (style) {
		case STYLE_WHOLE_NETWORK:
			this.showTitle = "Whole Network";
			this.fileTitle = "WholeNetwork";
			break;
		case STYLE_SERVICE_NETWORK:
			this.showTitle = "Service Network";
			this.fileTitle = "ServiceNetwork";
			break;
		}

		GridLayout gridLayout = new GridLayout(1, false);
		gridLayout.horizontalSpacing = 0;
		setLayout(gridLayout);
		setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		Composite cmpMain = new Composite(this, SWT.NONE);
		cmpMain.setLayout(new FormLayout());
		cmpMain.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

		txtOutput = new StyledText(cmpMain, SWT.BORDER | SWT.READ_ONLY
				| SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
		txtOutput.addModifyListener(new ModifyListener() {
			private Timer timer = new Timer(true);
			private TimerTask task;

			public void modifyText(ModifyEvent arg0) {
				if (!txtOutput.getVisible()) {
					txtOutput.setVisible(true);
				}
				txtOutput.setFocus();
				lblOutput.setText(txtOutput.getLine(txtOutput.getLineCount() - 1));
				if (task != null) {
					task.cancel();
				}
				task = new TimerTask() {
					@Override
					public void run() {
						Display.getDefault().syncExec(new Runnable() {
							public void run() {
								if (txtOutput.getVisible()) {
									txtOutput.setVisible(false);
								}
							}
						});
					}
				};
				timer.schedule(task, 3000);
			}
		});
		txtOutput.addFocusListener(new FocusAdapter() {
			@Override
			public void focusLost(FocusEvent e) {
				txtOutput.setVisible(false);
			}
		});
		FormData fd_txtOutput = new FormData();
		fd_txtOutput.top = new FormAttachment(100, -100);
		fd_txtOutput.bottom = new FormAttachment(100);
		fd_txtOutput.left = new FormAttachment(0);
		fd_txtOutput.right = new FormAttachment(100);
		txtOutput.setLayoutData(fd_txtOutput);
		txtOutput.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		txtOutput.setVisible(false);

		Composite cmpGraph = new Composite(cmpMain, SWT.NONE);
		FormData fd_cmpGraph = new FormData();
		fd_cmpGraph.top = new FormAttachment(0);
		fd_cmpGraph.bottom = new FormAttachment(100, -18);
		fd_cmpGraph.left = new FormAttachment(0);
		fd_cmpGraph.right = new FormAttachment(100);
		cmpGraph.setLayoutData(fd_cmpGraph);
		GridLayout gl_cmpGraph = new GridLayout(1, false);
		gl_cmpGraph.marginWidth = 0;
		gl_cmpGraph.marginHeight = 0;
		gl_cmpGraph.horizontalSpacing = 0;
		gl_cmpGraph.verticalSpacing = 0;
		cmpGraph.setLayout(gl_cmpGraph);

		Composite cmpGraphTitle = new Composite(cmpGraph, SWT.NONE);
		cmpGraphTitle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));
		cmpGraphTitle.setLayout(new GridLayout(1, false));

		lblGraphTitle = new Label(cmpGraphTitle, SWT.CENTER);
		lblGraphTitle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
				false, 1, 1));
		FontData fontData = FontDataClone.clone(Display.getCurrent()
				.getSystemFont().getFontData()[0]);
		fontData.setHeight(fontData.getHeight() + 1);
		fontData.setStyle(SWT.BOLD);
		Font font = new Font(Display.getCurrent(), fontData);
		lblGraphTitle.setFont(font);
		lblGraphTitle.setText("Graph");

		sashGraphDisplay = new SashForm(cmpGraph, SWT.NONE);
		sashGraphDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 1, 1));

		Composite cmpGraphLeft = new Composite(sashGraphDisplay, SWT.BORDER);
		GridLayout gl_cmpGraphLeft = new GridLayout(1, false);
		gl_cmpGraphLeft.verticalSpacing = 0;
		gl_cmpGraphLeft.horizontalSpacing = 0;
		gl_cmpGraphLeft.marginWidth = 0;
		gl_cmpGraphLeft.marginHeight = 0;
		cmpGraphLeft.setLayout(gl_cmpGraphLeft);

		Composite cmpGraphContentConfig = new Composite(cmpGraphLeft, SWT.NONE);
		GridData gd_cmpGraphContentConfig = new GridData(SWT.FILL, SWT.CENTER,
				false, false, 1, 1);
		gd_cmpGraphContentConfig.heightHint = 37;
		cmpGraphContentConfig.setLayoutData(gd_cmpGraphContentConfig);
		GridLayout gl_cmpGraphContentConfig = new GridLayout(4, false);
		cmpGraphContentConfig.setLayout(gl_cmpGraphContentConfig);

		Label lblGraphPaintStyle = new Label(cmpGraphContentConfig, SWT.NONE);
		lblGraphPaintStyle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				false, true, 1, 1));
		lblGraphPaintStyle.setText("Paint Style:");

		cmbGraphPaintStyle = new Combo(cmpGraphContentConfig, SWT.READ_ONLY);
		cmbGraphPaintStyle.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (graphPkg != null) {
					updateGraph();
				} else if (bgGraphPkg != null) {
					updateBGGraph();
				}
			}
		});
		cmbGraphPaintStyle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				false, true, 1, 1));
		cmbGraphPaintStyle.setItems(GRAPH_NODE_PAINT_STYLE);
		cmbGraphPaintStyle.select(GRAPH_NODE_PAINT_STYLE_IO_INT);

		Label lblNodeLabelStyle = new Label(cmpGraphContentConfig, SWT.NONE);
		lblNodeLabelStyle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				false, true, 1, 1));
		lblNodeLabelStyle.setText("Node Label:");

		cmbNodeLabelStyle = new Combo(cmpGraphContentConfig, SWT.READ_ONLY);
		cmbNodeLabelStyle.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (graphPkg != null) {
					updateGraph();
				} else if (bgGraphPkg != null) {
					updateBGGraph();
				}
			}
		});
		cmbNodeLabelStyle.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				false, true, 1, 1));
		cmbNodeLabelStyle.setItems(GRAPH_NODE_LABEL_STYLE);
		cmbNodeLabelStyle.select(GRAPH_NODE_LABEL_STYLE_SHORT_NAME_INT);

		Label lineLeft = new Label(cmpGraphLeft, SWT.SEPARATOR | SWT.HORIZONTAL);
		lineLeft.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false,
				1, 1));

		cmpGraphContent = new Composite(cmpGraphLeft, SWT.EMBEDDED);
		cmpGraphContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 1, 1));
		cmpGraphContent.setBackground(SWTResourceManager
				.getColor(SWT.COLOR_WHITE));
		cmpGraphContent.setVisible(true);

		frmGraphContent = SWT_AWT.new_Frame(cmpGraphContent);

		Composite cmpGraphRight = new Composite(sashGraphDisplay, SWT.BORDER);
		cmpGraphRight.addControlListener(new ControlAdapter() {
			@Override
			public void controlResized(ControlEvent e) {
				int[] w = sashGraphDisplay.getWeights();
				double w1 = 1.0d * sashGraphDisplay.getSize().x / (w[0] + w[1])
						* w[0];
				double w2 = 1.0d * sashGraphDisplay.getSize().x / (w[0] + w[1])
						* w[1];
				if (w1 < 410) {
					int min1 = (int) (1.0d * 410 / sashGraphDisplay.getSize().x * 1000);
					sashGraphDisplay
							.setWeights(new int[] { min1, 1000 - min1 });
				}
				if (w2 < 135) {
					int min2 = (int) (1.0d * 135 / sashGraphDisplay.getSize().x * 1000);
					sashGraphDisplay
							.setWeights(new int[] { 1000 - min2, min2 });
				}
			}
		});
		GridLayout gl_cmpGraphRight = new GridLayout(1, false);
		gl_cmpGraphRight.verticalSpacing = 0;
		gl_cmpGraphRight.horizontalSpacing = 0;
		gl_cmpGraphRight.marginWidth = 0;
		gl_cmpGraphRight.marginHeight = 0;
		cmpGraphRight.setLayout(gl_cmpGraphRight);

		Composite cmpGraphInfoStyleConfig = new Composite(cmpGraphRight,
				SWT.NONE);
		cmpGraphInfoStyleConfig.setLayout(new GridLayout(1, false));
		GridData gd_cmpGraphInfoStyleConfig = new GridData(SWT.FILL,
				SWT.CENTER, false, false, 1, 1);
		gd_cmpGraphInfoStyleConfig.heightHint = 37;
		cmpGraphInfoStyleConfig.setLayoutData(gd_cmpGraphInfoStyleConfig);

		Button btnGraphInfoDisplayConfig = new Button(cmpGraphInfoStyleConfig,
				SWT.NONE);
		btnGraphInfoDisplayConfig.setLayoutData(new GridData(SWT.LEFT,
				SWT.CENTER, false, true, 1, 1));
		btnGraphInfoDisplayConfig.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (ioDisplayConfig == null || degreeDisplayConfig == null
						|| execDisplayConfigGraph == null
						|| execDisplayConfigResult == null
						|| execDisplayConfigStats == null
						|| bgDisplayConfig == null
						|| bgFlowDisplayConfig == null
						|| bgServiceDisplayConfig == null) {
					return;
				}
				GraphInfoDisplayConfigDialog gui = new GraphInfoDisplayConfigDialog(
						getDisplay().getActiveShell(), ioDisplayConfig,
						degreeDisplayConfig, execDisplayConfigGraph,
						execDisplayConfigResult, execDisplayConfigStats,
						bgDisplayConfig, bgFlowDisplayConfig,
						bgServiceDisplayConfig);
				if (gui.open() == null) {
					return;
				}
				if (graphPkg != null) {
					updateGraphInfo(graphPkg.getGraphType());
				}
				if (bgGraphPkg != null) {
					updateBGGraphInfo(bgGraphPkg.getBGType());
				}
			}
		});
		btnGraphInfoDisplayConfig.setText("Graph Info Config");

		Label lineRight = new Label(cmpGraphRight, SWT.SEPARATOR
				| SWT.HORIZONTAL);
		lineRight.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false,
				false, 1, 1));

		txtGraphInfo = new StyledText(cmpGraphRight, SWT.FULL_SELECTION
				| SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL);
		txtGraphInfo.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true,
				1, 1));
		txtGraphInfo
				.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		sashGraphDisplay.setWeights(new int[] { 5, 3 });

		lblOutput = new Label(cmpMain, SWT.NONE);
		lblOutput.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				if (!txtOutput.getVisible()) {
					txtOutput.setVisible(true);
				}
				txtOutput.setFocus();
			}
		});
		FormData fd_lblOutput = new FormData();
		fd_lblOutput.top = new FormAttachment(cmpGraph);
		fd_lblOutput.bottom = new FormAttachment(100);
		fd_lblOutput.left = new FormAttachment(0);
		fd_lblOutput.right = new FormAttachment(100);
		lblOutput.setLayoutData(fd_lblOutput);

		Menu menu = new Menu(this, SWT.BAR);
		setMenuBar(menu);

		MenuItem mntmNetwork = new MenuItem(menu, SWT.CASCADE);
		mntmNetwork.setText("Network");

		Menu menuNetwork = new Menu(mntmNetwork);
		mntmNetwork.setMenu(menuNetwork);

		mntmDrawAcnode = new MenuItem(menuNetwork, SWT.CHECK);
		mntmDrawAcnode.setSelection(true);
		mntmDrawAcnode.setText("Acnode");

		MenuItem mntmDrawNetwork = new MenuItem(menuNetwork, SWT.NONE);
		mntmDrawNetwork.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildNetworkGraph()) {
					updateGraphSelection();
					drawGraph();
					updateGraphInfo(GraphPkg.NETWORK);
				}
			}
		});
		mntmDrawNetwork.setText("Network");

		MenuItem mntmDrawFlow = new MenuItem(menuNetwork, SWT.NONE);
		mntmDrawFlow.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildFlowGraph()) {
					updateGraphSelection();
					drawGraph();
					updateGraphInfo(GraphPkg.FLOW);
				}
			}
		});
		mntmDrawFlow.setText("Flow");

		MenuItem mntmBG = new MenuItem(menu, SWT.CASCADE);
		mntmBG.setText("Bipartite Graph");

		Menu menuBG = new Menu(mntmBG);
		mntmBG.setMenu(menuBG);

		MenuItem mntmBg = new MenuItem(menuBG, SWT.NONE);
		mntmBg.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBG(BGGraphPkg.BG)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG);
					updateBGGraphInfo(BGGraphPkg.BG);
				}
			}
		});
		mntmBg.setText("Bipartite Graph");

		MenuItem mntmBgSingleFlow = new MenuItem(menuBG, SWT.NONE);
		mntmBgSingleFlow.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBGOneGraph(BGGraphPkg.BG_ONE_FLOW)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_ONE_FLOW);
					updateBGGraphInfo(BGGraphPkg.BG_ONE_FLOW);
				}
			}
		});
		mntmBgSingleFlow.setText("Single Flow");

		MenuItem mntmBgSingleService = new MenuItem(menuBG, SWT.NONE);
		mntmBgSingleService.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBGOneGraph(BGGraphPkg.BG_ONE_SERVICE)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_ONE_SERVICE);
					updateBGGraphInfo(BGGraphPkg.BG_ONE_SERVICE);
				}
			}
		});
		mntmBgSingleService.setText("Single Service");

		new MenuItem(menuBG, SWT.SEPARATOR);

		MenuItem mntmBgFlowPart = new MenuItem(menuBG, SWT.NONE);
		mntmBgFlowPart.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBG(BGGraphPkg.BG_FLOW_PART)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_FLOW_PART);
					updateBGGraphInfo(BGGraphPkg.BG_FLOW_PART);
				}
			}
		});
		mntmBgFlowPart.setText("Flow Part");

		MenuItem mntmBgFlowPartSingle = new MenuItem(menuBG, SWT.NONE);
		mntmBgFlowPartSingle.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBGOneGraph(BGGraphPkg.BG_FLOW_PART_ONE)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_FLOW_PART_ONE);
					updateBGGraphInfo(BGGraphPkg.BG_FLOW_PART_ONE);
				}
			}
		});
		mntmBgFlowPartSingle.setText("Single Flow");

		new MenuItem(menuBG, SWT.SEPARATOR);

		MenuItem mntmBgServicePart = new MenuItem(menuBG, SWT.NONE);
		mntmBgServicePart.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBG(BGGraphPkg.BG_SERVICE_PART)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_SERVICE_PART);
					updateBGGraphInfo(BGGraphPkg.BG_SERVICE_PART);
				}
			}
		});
		mntmBgServicePart.setText("Service Part");

		MenuItem mntmBgServicePartSingle = new MenuItem(menuBG, SWT.NONE);
		mntmBgServicePartSingle.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (buildBGOneGraph(BGGraphPkg.BG_SERVICE_PART_ONE)) {
					updateBGGraphSelection();
					drawBGGraph(BGGraphPkg.BG_SERVICE_PART_ONE);
					updateBGGraphInfo(BGGraphPkg.BG_SERVICE_PART_ONE);
				}
			}
		});
		mntmBgServicePartSingle.setText("Single Service");

		MenuItem mntmSimulation = new MenuItem(menu, SWT.CASCADE);
		mntmSimulation.setText("Simulation");

		Menu menuSimulation = new Menu(mntmSimulation);
		mntmSimulation.setMenu(menuSimulation);

		MenuItem mntmSimParameters = new MenuItem(menuSimulation, SWT.NONE);
		mntmSimParameters.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (dataPkg == null) {
					return;
				}
				if (dataPkg.getNetworkExecParameterPkg() == null) {
					Printer.getInstance().append(txtOutput,
							"Network doesn't exist.", StringConstant.WARNING,
							Printer.COLOR_WARNING);
					return;
				}
				ExecParameterSettingDialog gui = new ExecParameterSettingDialog(
						getDisplay().getActiveShell(), "Network", dataPkg
								.getNetworkExecParameterPkg());
				gui.open();
			}
		});
		mntmSimParameters.setText("Parameters");

		MenuItem mntmSimExecute = new MenuItem(menuSimulation, SWT.NONE);
		mntmSimExecute.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				execute(null);
			}
		});
		mntmSimExecute.setText("Execute");

		MenuItem mntmSimExecuteExistInput = new MenuItem(menuSimulation,
				SWT.NONE);
		mntmSimExecuteExistInput.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				execute(dataPkg.getNetworkExecResultPkg().getExecResult()
						.getTaskExecMap());
			}
		});
		mntmSimExecuteExistInput.setText("Execute with Exist Input");

		new MenuItem(menuSimulation, SWT.SEPARATOR);

		MenuItem mntmSimAnalyze = new MenuItem(menuSimulation, SWT.NONE);
		mntmSimAnalyze.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (dataPkg == null) {
					return;
				}
				if (dataPkg.getNetworkExecResultPkg() == null) {
					return;
				}

				ServiceInfluenceDialog dialog = new ServiceInfluenceDialog(
						getDisplay().getActiveShell(), SWT.NONE, dataPkg);
				dialog.open();
			}
		});
		mntmSimAnalyze.setText("Analyze");

		new MenuItem(menuSimulation, SWT.SEPARATOR);

		MenuItem mntmSimSave = new MenuItem(menuSimulation, SWT.NONE);
		mntmSimSave.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveExecResult();
			}
		});
		mntmSimSave.setText("Save");

		MenuItem mntmSimSaveFlow = new MenuItem(menuSimulation, SWT.NONE);
		mntmSimSaveFlow.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveFlowExecResult();
			}
		});
		mntmSimSaveFlow.setText("Save Flow");

		MenuItem mntmChart = new MenuItem(menu, SWT.CASCADE);
		mntmChart.setText("Chart");

		Menu menuChart = new Menu(mntmChart);
		mntmChart.setMenu(menuChart);

		MenuItem mntmChartNetwork = new MenuItem(menuChart, SWT.CASCADE);
		mntmChartNetwork.setText("Network");

		Menu menuChartNetwork = new Menu(mntmChartNetwork);
		mntmChartNetwork.setMenu(menuChartNetwork);

		MenuItem mntmChartNetworkDegreeDis = new MenuItem(menuChartNetwork,
				SWT.NONE);
		mntmChartNetworkDegreeDis.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				NetworkStatsChart.getInstance().create(
						NetworkStats.DEGREE_DISTRIBUTION, getDisplay(),
						showTitle, showTitle + " Degree", "Count", dataPkg);
			}
		});
		mntmChartNetworkDegreeDis.setText("Degree Distribution");

		MenuItem mntmChartBG = new MenuItem(menuChart, SWT.CASCADE);
		mntmChartBG.setText("Bipartite Graph");

		Menu menuChartBG = new Menu(mntmChartBG);
		mntmChartBG.setMenu(menuChartBG);

		MenuItem mntmNetworkServiceDgree = new MenuItem(menuChartBG, SWT.NONE);
		mntmNetworkServiceDgree.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				BGNetworkStatsChart.getInstance().create(
						BGNetworkStats.NETWORK_SERVICE_DEGREE, getDisplay(),
						"Bipartite Graph", "Service Degree", "Count", dataPkg);
			}
		});
		mntmNetworkServiceDgree.setText("Network Service Dgree Dist");

		MenuItem mntmNetworkFlowDgree = new MenuItem(menuChartBG, SWT.NONE);
		mntmNetworkFlowDgree.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				BGNetworkStatsChart.getInstance().create(
						BGNetworkStats.NETWORK_FLOW_DEGREE, getDisplay(),
						"Bipartite Graph", "Flow Degree", "Count", dataPkg);
			}
		});
		mntmNetworkFlowDgree.setText("Network Flow Dgree Dist");

		MenuItem mntmChartExecution = new MenuItem(menuChart, SWT.CASCADE);
		mntmChartExecution.setText("Execution");

		Menu menuChartExecution = new Menu(mntmChartExecution);
		mntmChartExecution.setMenu(menuChartExecution);

		MenuItem menuChartExecExecTimeDis = new MenuItem(menuChartExecution,
				SWT.NONE);
		menuChartExecExecTimeDis.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				ExecStatsChart.getInstance().create(
						ExecStats.EXECUTION_TIME_DISTRIBUTION, getDisplay(),
						showTitle, "Execution Time", "Count", dataPkg);
			}
		});
		menuChartExecExecTimeDis.setText("Execution Time Distribution");

		new MenuItem(menuChartExecution, SWT.SEPARATOR);

		MenuItem mntmChartExecFlowAvgExecTimeDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowAvgExecTimeDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_AVG_EXEC_TIME_DISTRIBUTION,
								getDisplay(), showTitle, "Avg Execution Time",
								"Count", dataPkg);
					}
				});
		mntmChartExecFlowAvgExecTimeDis
				.setText("Flow Avg Execution Time Distribution");

		MenuItem mntmChartExecFlowMaxExecTimeDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowMaxExecTimeDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_MAX_EXEC_TIME_DISTRIBUTION,
								getDisplay(), showTitle, "Max Execution Time",
								"Count", dataPkg);
					}
				});
		mntmChartExecFlowMaxExecTimeDis
				.setText("Flow Max Execution Time Distribution");

		MenuItem mntmChartExecFlowMinExecTimeDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowMinExecTimeDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_MIN_EXEC_TIME_DISTRIBUTION,
								getDisplay(), showTitle, "Min Execution Time",
								"Count", dataPkg);
					}
				});
		mntmChartExecFlowMinExecTimeDis
				.setText("Flow Min Execution Time Distribution");

		MenuItem mntmChartExecFlowTotalCountDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowTotalCountDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_TOTAL_COUNT_DISTRIBUTION,
								getDisplay(), showTitle,
								"Flow Total Task Count", "Count", dataPkg);
					}
				});
		mntmChartExecFlowTotalCountDis
				.setText("Flow Total Task Count Distribution");

		MenuItem mntmChartExecFlowExecCountDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowExecCountDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_EXECUTED_COUNT_DISTRIBUTION,
								getDisplay(), showTitle,
								"Flow Executed Task Count", "Count", dataPkg);
					}
				});
		mntmChartExecFlowExecCountDis
				.setText("Flow Executed Task Count Distribution");

		MenuItem mntmChartExecFlowUnfinishedCountDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowUnfinishedCountDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_UNFINISHED_COUNT_DISTRIBUTION,
								getDisplay(), showTitle,
								"Flow Unfinished Task Count", "Count", dataPkg);
					}
				});
		mntmChartExecFlowUnfinishedCountDis
				.setText("Flow Unfinished Task Count Distribution");

		MenuItem mntmChartExecFlowOverAbilityTimeDis = new MenuItem(
				menuChartExecution, SWT.NONE);
		mntmChartExecFlowOverAbilityTimeDis
				.addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						ExecStatsChart.getInstance().create(
								ExecStats.FLOW_OVER_ABILITY_TIME_DISTRIBUTION,
								getDisplay(), showTitle,
								"Flow Over Ability Time", "Count", dataPkg);
					}
				});
		mntmChartExecFlowOverAbilityTimeDis
				.setText("Flow Over Ability Time Distribution");

		createContents();
	}

	/**
	 * Create contents of the shell.
	 */
	protected void createContents() {
		setText("Analyze " + this.showTitle);
		setImage(SWTResourceManager.getImage(NetworkAnalyzerGUI.class,
				"/res/icon.png"));
		setSize(1024, 700);
		setMinimumSize(1024, 700);
		setLocation(12, 10);
		setMaximized(true);
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

	@Override
	public void dispose() {
		super.dispose();
		main.dispose();
	}

	protected void setNetwork(DataPkg dataPkg) {
		if (dataPkg == null) {
			return;
		}

		/* Clear dataPkg */
		this.dataPkg = null;
		flow = null;
		clearGraph();

		/* Set Network */
		this.dataPkg = dataPkg;

		if (this.dataPkg.getNetworkPkg() != null) {
			Network network = this.dataPkg.getNetworkPkg().getNetwork();
			HashMap<Flow, Integer> flowWeightMap = new HashMap<Flow, Integer>();
			for (Flow f : network.getFlowMap().values()) {
				flowWeightMap.put(f, 1);
			}
			HashMap<Flow, Integer> flowRelDeadlineMap = new HashMap<Flow, Integer>();
			for (Flow f : network.getFlowMap().values()) {
				flowRelDeadlineMap.put(f, f.getNodeSet().size());
			}
			HashMap<Service, Integer> serviceAbilityMap = new HashMap<Service, Integer>();
			for (Service s : network.getServiceMap().values()) {
				serviceAbilityMap.put(s, s.getInstanceSet().size());
			}
			// for (Flow f : network.getFlowMap().values()) {
			// for (Node n : f.getNodeSet()) {
			// int a;
			// if (n.getParentCount() == 0) {
			// a = 1;
			// } else {
			// a = n.getParentCount();
			// }
			// serviceAbilityMap.put(n.getService(),
			// serviceAbilityMap.get(n.getService()) + a);
			// }
			// }
			HashMap<Service, Integer> serviceScheduleMap = new HashMap<Service, Integer>();
			for (Service s : network.getServiceMap().values()) {
				serviceScheduleMap.put(s, Service.SCH_FIFO);
			}
			ExecParameterPkg pkg = new ExecParameterPkg();
			pkg.setTotalStep(1000);
			pkg.setNormalSpeed(network.getFlowMap().size());
			pkg.setFlowWeightMap(flowWeightMap);
			pkg.setFlowRelDeadlineMap(flowRelDeadlineMap);
			pkg.setServiceAbilityMap(serviceAbilityMap);
			pkg.setServiceScheduleMap(serviceScheduleMap);
			pkg.setDefaultFlowWeightMap(new HashMap<Flow, Integer>(
					flowWeightMap));
			pkg.setDefaultFlowRelDeadlineMap(new HashMap<Flow, Integer>(
					flowRelDeadlineMap));
			pkg.setDefaultServiceAbilityMap(new HashMap<Service, Integer>(
					serviceAbilityMap));
			pkg.setDefaultServiceScheduleMap(new HashMap<Service, Integer>(
					serviceScheduleMap));
			pkg.setHasPeak(false);
			pkg.setPeakA(1);
			pkg.setPeakB(1);
			pkg.setPeakSpeed(pkg.getNormalSpeed());
			pkg.setHasValley(false);
			pkg.setValleyA(1);
			pkg.setValleyB(1);
			pkg.setValleySpeed(pkg.getNormalSpeed());
			this.dataPkg.setNetworkExecParameterPkg(pkg);
		}

		/* Show Network */
		this.setFocus();

		if (this.dataPkg.getNetworkPkg() == null) {
			return;
		}

		Network network = this.dataPkg.getNetworkPkg().getNetwork();

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt("Network", StringConstant.TITLE));
		info.add(new TupleStrInt(network.getFlowMap().size() + " flows",
				StringConstant.CONTENT));
		info.add(new TupleStrInt(network.getNodeSet().size() + " nodes",
				StringConstant.CONTENT));
		Printer.getInstance().append(txtOutput, info, SWT.COLOR_BLACK);

		HashSet<URI> set = new HashSet<URI>();
		for (Node n : network.getNodeSet()) {
			set.add(n.getService().getType());
		}
		info.add(new TupleStrInt("Service Type", StringConstant.TITLE));
		for (URI uri : set) {
			info.add(new TupleStrInt(uri.toString(), StringConstant.CONTENT));
		}
		Printer.getInstance().append(txtOutput, info, SWT.COLOR_BLACK);
	}

	private void clearGraph() {
		this.graphPkg = null;
		this.bgGraphPkg = null;
		lblGraphTitle.setText("Graph");
		frmGraphContent.removeAll();
		frmGraphContent.pack();
		Printer.getInstance().clear(txtGraphInfo);
	}

	private void updateGraphSelection() {
		if (this.graphStyle != GRAPH_STYLE_GRAPH) {
			cmbGraphPaintStyle.setItems(GRAPH_NODE_PAINT_STYLE);
			cmbGraphPaintStyle.select(GRAPH_NODE_PAINT_STYLE_IO_INT);
			cmbNodeLabelStyle.setItems(GRAPH_NODE_LABEL_STYLE);
			cmbNodeLabelStyle.select(GRAPH_NODE_LABEL_STYLE_SHORT_NAME_INT);
			this.graphStyle = GRAPH_STYLE_GRAPH;
		}
	}

	private void updateBGGraphSelection() {
		if (this.graphStyle != GRAPH_STYLE_BG) {
			cmbGraphPaintStyle.setItems(BGGRAPH_NODE_PAINT_STYLE);
			cmbGraphPaintStyle.select(BGGRAPH_NODE_PAINT_STYLE_BG_INT);
			cmbNodeLabelStyle.setItems(BGGRAPH_NODE_LABEL_STYLE);
			cmbNodeLabelStyle.select(BGGRAPH_NODE_LABEL_STYLE_SHORT_NAME_INT);
			this.graphStyle = GRAPH_STYLE_BG;
		}
	}

	private boolean buildNetworkGraph() {
		if (dataPkg == null) {
			return false;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return false;
		}

		Network network = networkPkg.getNetwork();
		if (ErrorChecker.getInstance().isNull(network, txtOutput, "Network")
				|| ErrorChecker.getInstance().isEmpty(network.getNodeSet(),
						txtOutput, "Network")) {
			return false;
		}

		clearGraph();
		Graph<Node, Link> graph = GraphMaker.getInstance().make(network,
				mntmDrawAcnode.getSelection());
		if (ErrorChecker.getInstance().isNull(graph, txtOutput, "Graph")) {
			return false;
		}

		GraphStats graphStats = GraphStatsAnalyzer.getInstance().analyze(
				"Network", graph);
		if (ErrorChecker.getInstance().isNull(graphStats, txtOutput,
				"Graph Stats")) {
			return false;
		}

		this.graphPkg = new GraphPkg();
		this.graphPkg.setGraph(graph);
		this.graphPkg.setGraphName("Network");
		this.graphPkg.setGraphStats(graphStats);
		this.graphPkg.setGraphType(GraphPkg.NETWORK);
		this.bgGraphPkg = null;

		return true;
	}

	private boolean buildFlowGraph() {
		if (dataPkg == null) {
			return false;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return false;
		}

		Network network = networkPkg.getNetwork();
		if (ErrorChecker.getInstance().isNull(network, txtOutput, "Network")
				|| ErrorChecker.getInstance().isEmpty(network.getNodeSet(),
						txtOutput, "Network")) {
			return false;
		}

		String flowName = this.openChooseDialog(network.getFlowMap().keySet(),
				"Flow");
		if (flowName == null) {
			return false;
		}

		String graphFlowName = "Flow" + "(" + flowName + ")";

		Flow flow = network.getFlowMap().get(flowName);
		if (ErrorChecker.getInstance().isNull(flow, txtOutput, graphFlowName)
				|| ErrorChecker.getInstance().isEmpty(flow.getNodeSet(),
						txtOutput, graphFlowName)) {
			return false;
		}

		clearGraph();
		Graph<Node, Link> graph = GraphMaker.getInstance().make(flow,
				mntmDrawAcnode.getSelection());
		if (ErrorChecker.getInstance().isNull(graph, txtOutput, "Graph")) {
			return false;
		}

		GraphStats graphStats = GraphStatsAnalyzer.getInstance().analyze(
				flowName, graph);
		if (ErrorChecker.getInstance().isNull(graphStats, txtOutput,
				"Graph Stats")) {
			return false;
		}

		this.flow = flow;

		this.graphPkg = new GraphPkg();
		this.graphPkg.setGraph(graph);
		this.graphPkg.setGraphName(flowName);
		this.graphPkg.setGraphStats(graphStats);
		this.graphPkg.setGraphType(GraphPkg.FLOW);
		this.bgGraphPkg = null;

		return true;
	}

	private boolean buildBG(int bgType) {
		if (dataPkg == null) {
			return false;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return false;
		}

		BGNetwork network = networkPkg.getBgNetwork();
		HashMap<Flow, BGNode> flowMap = networkPkg.getBgFlowMap();
		HashMap<Service, BGNode> serviceMap = networkPkg.getBgServiceMap();

		if (ErrorChecker.getInstance().isNull(network, txtOutput,
				"Bipartite Graph")
				|| ErrorChecker.getInstance().isEmpty(flowMap, txtOutput,
						"Bipartite Graph")
				|| ErrorChecker.getInstance().isEmpty(serviceMap, txtOutput,
						"Bipartite Graph")) {
			return false;
		}

		clearGraph();
		String graphName;
		Graph<BGNode, BGLink> graph = null;

		switch (bgType) {
		case BGGraphPkg.BG:
			graphName = "Bipartite Graph";
			graph = BGGraphMaker.getInstance().make(network,
					mntmDrawAcnode.getSelection());
			break;
		case BGGraphPkg.BG_FLOW_PART:
			graphName = "Bipartite Graph Flow Part";
			graph = BGGraphMaker.getInstance().make(flowMap.values(),
					mntmDrawAcnode.getSelection());
			break;
		case BGGraphPkg.BG_SERVICE_PART:
			graphName = "Bipartite Graph Service Part";
			graph = BGGraphMaker.getInstance().make(serviceMap.values(),
					mntmDrawAcnode.getSelection());
			break;
		default:
			return false;
		}

		if (ErrorChecker.getInstance().isNull(graph, txtOutput,
				"Bipartite Graph")) {
			return false;
		}

		this.bgGraphPkg = new BGGraphPkg();
		this.bgGraphPkg.setGraph(graph);
		this.bgGraphPkg.setGraphName(graphName);
		this.bgGraphPkg.setBGType(bgType);
		this.graphPkg = null;

		return true;
	}

	private boolean buildBGOneGraph(int bgType) {
		if (dataPkg == null) {
			return false;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return false;
		}

		Network network = networkPkg.getNetwork();
		if (ErrorChecker.getInstance().isNull(network, txtOutput, "Network")
				|| ErrorChecker.getInstance().isEmpty(network.getNodeSet(),
						txtOutput, "Network")) {
			return false;
		}

		String graphName;
		String chooseDialogTitle;
		Set<String> nameSet;

		switch (bgType) {
		case BGGraphPkg.BG_ONE_FLOW:
		case BGGraphPkg.BG_FLOW_PART_ONE:
			chooseDialogTitle = "Flow";
			nameSet = networkPkg.getNetwork().getFlowMap().keySet();
			break;
		case BGGraphPkg.BG_ONE_SERVICE:
		case BGGraphPkg.BG_SERVICE_PART_ONE:
			chooseDialogTitle = "Service";
			nameSet = networkPkg.getNetwork().getServiceMap().keySet();
			break;
		default:
			return false;
		}

		String name = this.openChooseDialog(nameSet, chooseDialogTitle);
		if (name == null) {
			return false;
		}

		BGNode node = null;
		Flow flow;
		Service svc;

		switch (bgType) {
		case BGGraphPkg.BG_ONE_FLOW:
			graphName = name + " Neighbors  in BG";
			flow = network.getFlowMap().get(name);
			if (flow != null) {
				node = networkPkg.getBgNetwork().getFlowMap().get(flow);
			}
			break;
		case BGGraphPkg.BG_FLOW_PART_ONE:
			graphName = name + " Neighbors in BG Flow Part";
			flow = network.getFlowMap().get(name);
			if (flow != null) {
				node = networkPkg.getBgFlowMap().get(flow);
			}
			break;
		case BGGraphPkg.BG_ONE_SERVICE:
			graphName = name + " Neighbors  in BG";
			svc = network.getServiceMap().get(name);
			if (svc != null) {
				node = networkPkg.getBgNetwork().getServiceMap().get(svc);
			}
			break;
		case BGGraphPkg.BG_SERVICE_PART_ONE:
			graphName = name + " Neighbors in BG Service Part";
			svc = network.getServiceMap().get(name);
			if (svc != null) {
				node = networkPkg.getBgServiceMap().get(svc);
			}
			break;
		default:
			return false;
		}

		if (ErrorChecker.getInstance().isNull(node, txtOutput, name)) {
			return false;
		}

		clearGraph();
		Graph<BGNode, BGLink> graph = BGGraphMaker.getInstance().makeNeighbor(
				node);
		if (ErrorChecker.getInstance().isNull(graph, txtOutput, graphName)) {
			return false;
		}

		this.bgNode = node;

		this.bgGraphPkg = new BGGraphPkg();
		this.bgGraphPkg.setGraph(graph);
		this.bgGraphPkg.setGraphName(graphName);
		this.bgGraphPkg.setBGType(bgType);
		this.graphPkg = null;

		return true;
	}

	private void drawGraph() {
		if (this.graphPkg == null) {
			return;
		}

		lblGraphTitle.setText(this.graphPkg.getGraphName());

		if (this.graphPkg.getGraph().getVertexCount() > GRAPH_NODE_UPPER_BOUND) {
			Printer.getInstance().append(
					txtOutput,
					"Cannot draw the graph \"" + this.graphPkg.getGraphName()
							+ "\", because nodes are more than "
							+ GRAPH_NODE_UPPER_BOUND + ".",
					StringConstant.WARNING, Printer.COLOR_WARNING);
		} else if (this.graphPkg.getGraph().getEdgeCount() > GRAPH_LINK_UPPER_BOUND) {
			Printer.getInstance().append(
					txtOutput,
					"Cannot draw the graph \"" + this.graphPkg.getGraphName()
							+ "\", because links are more than "
							+ GRAPH_LINK_UPPER_BOUND + ".",
					StringConstant.WARNING, Printer.COLOR_WARNING);
		} else {
			this.graphPkg.setGraphViewer(VisualizationServerBuilder
					.getInstance().build(this.graphPkg.getGraph(),
							cmpGraphContent.getSize().x,
							cmpGraphContent.getSize().y));

			if (this.graphPkg.getGraphViewer() != null) {
				this.updateGraphContent();
				this.graphPkg.getGraphViewer().setBackground(Color.WHITE);
				frmGraphContent.add(this.graphPkg.getGraphViewer());
				frmGraphContent.pack();
			}
		}
	}

	private void drawBGGraph(int bgType) {
		if (this.bgGraphPkg == null) {
			return;
		}

		lblGraphTitle.setText(this.bgGraphPkg.getGraphName());

		if (this.bgGraphPkg.getGraph().getVertexCount() > GRAPH_NODE_UPPER_BOUND) {
			Printer.getInstance().append(
					txtOutput,
					"Cannot draw the graph \"" + this.bgGraphPkg.getGraphName()
							+ "\", because nodes are more than "
							+ GRAPH_NODE_UPPER_BOUND + ".",
					StringConstant.WARNING, Printer.COLOR_WARNING);
		} else if (this.bgGraphPkg.getGraph().getEdgeCount() > GRAPH_LINK_UPPER_BOUND) {
			Printer.getInstance().append(
					txtOutput,
					"Cannot draw the graph \"" + this.bgGraphPkg.getGraphName()
							+ "\", because links are more than "
							+ GRAPH_LINK_UPPER_BOUND + ".",
					StringConstant.WARNING, Printer.COLOR_WARNING);
		} else {
			this.bgGraphPkg.setGraphViewer(BGVisualizationServerBuilder
					.getInstance().build(this.bgGraphPkg.getGraph(),
							cmpGraphContent.getSize().x,
							cmpGraphContent.getSize().y));

			if (this.bgGraphPkg.getGraphViewer() != null) {
				this.updateBGGraphContent(bgType);
				this.bgGraphPkg.getGraphViewer().setBackground(Color.WHITE);
				frmGraphContent.add(this.bgGraphPkg.getGraphViewer());
				frmGraphContent.pack();
			}
		}
	}

	private void updateGraph() {
		if (this.graphPkg == null) {
			return;
		}
		this.updateGraphContent();
		this.updateGraphInfo(this.graphPkg.getGraphType());

		this.layout();
	}

	private void updateBGGraph() {
		if (this.bgGraphPkg == null) {
			return;
		}
		this.updateBGGraphContent(this.bgGraphPkg.getBGType());
		this.updateBGGraphInfo(this.bgGraphPkg.getBGType());

		this.layout();
	}

	private void updateGraphContent() {
		if (dataPkg == null) {
			return;
		}

		if (this.graphPkg == null) {
			return;
		}

		ExecResultPkg execResultPkg = this.dataPkg.getNetworkExecResultPkg();

		NodeToPaintTransformer n2paint = null;
		NodeToLabelTransformer n2label = null;
		EdgeToStrokeTransformer e2stroke = null;

		String text;
		text = cmbGraphPaintStyle.getText();
		if (text.equals(GRAPH_NODE_PAINT_STYLE_IO_STR)) {
			n2paint = NodeToPaintTransformer.makeInstanceIO();
		} else if (text.equals(GRAPH_NODE_PAINT_STYLE_EXECUTION_STR)) {
			if (execResultPkg != null && execResultPkg.getExecStats() != null) {
				n2paint = NodeToPaintTransformer
						.makeInstanceCount(execResultPkg.getExecStats()
								.getServiceExecCountMap());
			} else {
				n2paint = NodeToPaintTransformer.makeInstanceError();
			}
		} else if (text.equals(GRAPH_NODE_PAINT_STYLE_DEGREE_STR)) {
			if (this.graphPkg.getGraphStats() != null) {
				n2paint = NodeToPaintTransformer
						.makeInstanceDegree(this.graphPkg.getGraphStats()
								.getDegreeDistribution().keySet());
			} else {
				n2paint = NodeToPaintTransformer.makeInstanceError();
			}
		}

		text = cmbNodeLabelStyle.getText();
		if (text.equals(GRAPH_NODE_LABEL_STYLE_BLANK_STR)) {
			n2label = NodeToLabelTransformer.makeInstanceBlank();
		} else if (text.equals(GRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR)) {
			n2label = NodeToLabelTransformer.makeInstanceShortName();
		} else if (text.equals(GRAPH_NODE_LABEL_STYLE_NAME_STR)) {
			n2label = NodeToLabelTransformer.makeInstanceName();
		}

		e2stroke = EdgeToStrokeTransformer.makeInstance();

		if (this.graphPkg.getGraphViewer() != null) {
			if (n2paint != null) {
				this.graphPkg.getGraphViewer().getRenderContext()
						.setVertexFillPaintTransformer(n2paint);
			}
			if (n2label != null) {
				this.graphPkg.getGraphViewer().getRenderContext()
						.setVertexLabelTransformer(n2label);
			}
			if (e2stroke != null) {
				this.graphPkg.getGraphViewer().getRenderContext()
						.setEdgeStrokeTransformer(e2stroke);
			}
			this.graphPkg.getGraphViewer().repaint(10);
		}
	}

	private void updateBGGraphContent(int bgType) {
		if (dataPkg == null) {
			return;
		}

		if (this.bgGraphPkg == null) {
			return;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();

		BGNodeToPaintTransformer n2paint = null;
		BGNodeToLabelTransformer n2label = null;

		String text;
		text = cmbGraphPaintStyle.getText();
		if (text.equals(BGGRAPH_NODE_PAINT_STYLE_BG_STR)) {
			if (networkPkg != null) {
				switch (bgType) {
				case BGGraphPkg.BG:
				case BGGraphPkg.BG_ONE_FLOW:
				case BGGraphPkg.BG_ONE_SERVICE:
					n2paint = new BGNodeToPaintTransformer(
							networkPkg.getBgNetwork());
					break;
				case BGGraphPkg.BG_FLOW_PART:
				case BGGraphPkg.BG_FLOW_PART_ONE:
					n2paint = new BGNodeToPaintTransformer(networkPkg
							.getBgFlowMap().values());
					break;
				case BGGraphPkg.BG_SERVICE_PART:
				case BGGraphPkg.BG_SERVICE_PART_ONE:
					n2paint = new BGNodeToPaintTransformer(networkPkg
							.getBgServiceMap().values());
					break;
				}
			} else {
				n2paint = new BGNodeToPaintTransformer();
			}
		}

		text = cmbNodeLabelStyle.getText();
		if (text.equals(BGGRAPH_NODE_LABEL_STYLE_BLANK_STR)) {
			n2label = BGNodeToLabelTransformer.makeInstanceBlank();
		} else if (text.equals(BGGRAPH_NODE_LABEL_STYLE_SHORT_NAME_STR)) {
			n2label = BGNodeToLabelTransformer.makeInstanceShortName();
		} else if (text.equals(BGGRAPH_NODE_LABEL_STYLE_NAME_STR)) {
			n2label = BGNodeToLabelTransformer.makeInstanceName();
		}

		if (this.bgGraphPkg.getGraphViewer() != null) {
			if (n2paint != null) {
				this.bgGraphPkg.getGraphViewer().getRenderContext()
						.setVertexFillPaintTransformer(n2paint);
			}
			if (n2label != null) {
				this.bgGraphPkg.getGraphViewer().getRenderContext()
						.setVertexLabelTransformer(n2label);
			}
			this.bgGraphPkg.getGraphViewer().repaint(10);
		}
	}

	private void updateGraphInfo(int graphType) {
		if (dataPkg == null) {
			return;
		}

		if (ErrorChecker.getInstance().isNull(this.graphPkg, txtOutput,
				"Network")) {
			return;
		}

		NetworkPkg networkPkg;
		ExecResultPkg execResultPkg;
		Flow flow = null;
		switch (graphType) {
		case GraphPkg.NETWORK:
			execResultPkg = this.dataPkg.getNetworkExecResultPkg();
			networkPkg = this.dataPkg.getNetworkPkg();
			break;
		case GraphPkg.FLOW:
			if (this.flow == null) {
				return;
			}
			execResultPkg = this.dataPkg.getNetworkExecResultPkg();
			networkPkg = this.dataPkg.getNetworkPkg();
			flow = this.flow;
			break;
		default:
			return;
		}

		ArrayList<TupleStrInt> info = null;

		String text = cmbGraphPaintStyle.getText();
		if (text.equals(GRAPH_NODE_PAINT_STYLE_IO_STR)) {

			switch (graphType) {
			case GraphPkg.NETWORK:
				info = IOGenerator.getInstance().generate(
						this.graphPkg.getGraphStats(),
						networkPkg.getNetworkStats(), ioDisplayConfig);
				break;
			case GraphPkg.FLOW:
				info = IOGenerator.getInstance().generate(
						this.graphPkg.getGraphStats(),
						networkPkg.getNetworkStats(), ioDisplayConfig, flow);
				break;
			}
		} else if (text.equals(GRAPH_NODE_PAINT_STYLE_EXECUTION_STR)) {
			if (!ErrorChecker.getInstance().isNull(execResultPkg, txtOutput,
					"Execution Result")) {
				switch (graphType) {
				case GraphPkg.NETWORK:
					info = ExecGenerator.getInstance().generate(
							this.graphPkg.getGraphStats(),
							execResultPkg.getExecResult(),
							execResultPkg.getExecStats(),
							execDisplayConfigGraph, execDisplayConfigResult,
							execDisplayConfigStats);
					break;
				case GraphPkg.FLOW:
					info = ExecGenerator.getInstance().generate(
							this.graphPkg.getGraphStats(),
							execResultPkg.getExecResult(),
							execResultPkg.getExecStats(),
							execDisplayConfigGraph, execDisplayConfigResult,
							execDisplayConfigStats, flow);
					break;
				}
			}
		} else if (text.equals(GRAPH_NODE_PAINT_STYLE_DEGREE_STR)) {
			info = DegreeGenerator.getInstance().generate(
					this.graphPkg.getGraphStats(), degreeDisplayConfig);
		}

		Printer.getInstance().clear(txtGraphInfo);
		if (info != null) {
			if (info.size() > 0) {
				Printer.getInstance().append(txtGraphInfo, info,
						SWT.COLOR_DARK_GREEN);
			}
		}

		txtGraphInfo.setTopIndex(0);
		lblOutput.setText("");
	}

	private void updateBGGraphInfo(int bgType) {
		if (dataPkg == null) {
			return;
		}

		if (this.bgGraphPkg == null) {
			return;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return;
		}

		ArrayList<TupleStrInt> info = null;

		String text = cmbGraphPaintStyle.getText();
		if (text.equals(BGGRAPH_NODE_PAINT_STYLE_BG_STR)) {
			switch (bgType) {
			case BGGraphPkg.BG:
				info = BGGenerator.getInstance().generate(
						networkPkg.getBgNetworkStats(), bgDisplayConfig);
				break;
			case BGGraphPkg.BG_FLOW_PART:
				info = BGGenerator.getInstance().generate(
						networkPkg.getBgNetworkStats(), bgFlowDisplayConfig);
				break;
			case BGGraphPkg.BG_SERVICE_PART:
				info = BGGenerator.getInstance().generate(
						networkPkg.getBgNetworkStats(), bgServiceDisplayConfig);
				break;
			case BGGraphPkg.BG_ONE_FLOW:
			case BGGraphPkg.BG_ONE_SERVICE:
			case BGGraphPkg.BG_FLOW_PART_ONE:
			case BGGraphPkg.BG_SERVICE_PART_ONE:
				if (bgNode != null && bgGraphPkg != null) {
					info = BGOneGenerator.getInstance().generate(
							bgGraphPkg.getGraphName(), this.bgNode);
				}
				break;
			}
		}

		Printer.getInstance().clear(txtGraphInfo);
		if (info != null) {
			if (info.size() > 0) {
				Printer.getInstance().append(txtGraphInfo, info,
						SWT.COLOR_DARK_GREEN);
			}
		}

		txtGraphInfo.setTopIndex(0);
		lblOutput.setText("");
	}

	private boolean execute(
			final TreeMap<Integer, TaskExecResult> existTaskExecMap) {
		if (dataPkg == null) {
			return false;
		}

		NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return false;
		}

		final ExecParameterPkg execParameter = this.dataPkg
				.getNetworkExecParameterPkg();
		if (ErrorChecker.getInstance().isNull(execParameter, txtOutput,
				"Execution Parameter")
				|| ErrorChecker.getInstance().isEmpty(
						execParameter.getFlowWeightMap(), txtOutput,
						"Flow Weights")
				|| ErrorChecker.getInstance().isEmpty(
						execParameter.getFlowRelDeadlineMap(), txtOutput,
						"Flow Relative Deadlines")
				|| ErrorChecker.getInstance().isEmpty(
						execParameter.getServiceAbilityMap(), txtOutput,
						"Service Abilities")
				|| ErrorChecker.getInstance().isEmpty(
						execParameter.getServiceScheduleMap(), txtOutput,
						"Service Schedules")) {
			return false;
		}

		Network network = networkPkg.getNetwork();
		if (ErrorChecker.getInstance().isNull(network, txtOutput, "Network")
				|| ErrorChecker.getInstance().isEmpty(network.getNodeSet(),
						txtOutput, "Network")) {
			return false;
		}

		Printer.getInstance().append(txtOutput, "Start executing...",
				StringConstant.TITLE, SWT.COLOR_BLACK);

		final Executor executor = new Executor(network, execParameter);

		final ProcessingMessageBox executingMessage = new ProcessingMessageBox(
				super.getDisplay().getActiveShell(), "Executing");

		CusListener listener = new CusListener() {
			@Override
			public void occur(Object e) {
				if (executingMessage.isAlive()) {
					executingMessage.setProgress(((int) e) + 1,
							execParameter.getTotalStep());
				}
			}
		};
		executor.setListener(listener);

		SuccessThread thread = new SuccessThread("Network Executing Thread") {
			@Override
			public void run() {
				dataPkg.setNetworkExecResultPkg(null);

				ExecResult eresult;
				if (existTaskExecMap == null) {
					eresult = executor.execute();
				} else {
					eresult = executor.execute(existTaskExecMap);
				}
				ExecResultPkg eresultpkg = new ExecResultPkg();
				eresultpkg.setExecResult(eresult);
				eresultpkg.setExecStats(ExecStatsAnalyzer.getInstance()
						.analyze(eresult));

				dataPkg.setNetworkExecResultPkg(eresultpkg);

				synchronized (this) {
					try {
						wait(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				Display.getDefault().syncExec(new Runnable() {
					public void run() {
						if (buildNetworkGraph()) {
							updateGraphSelection();
							cmbGraphPaintStyle
									.select(GRAPH_NODE_PAINT_STYLE_EXECUTION_INT);
							drawGraph();
							updateGraphInfo(GraphPkg.NETWORK);

							Printer.getInstance().append(txtOutput,
									"Executing succeeds.",
									StringConstant.TITLE, SWT.COLOR_BLACK);

							isSuccess = true;
						} else {
							isSuccess = false;
						}
					}
				});
				executingMessage.close();
			}
		};
		executingMessage.setThread(thread);
		thread.start();

		if (thread.isAlive()) {
			executingMessage.open();
		}

		if (!thread.isSuccess()) {
			Printer.getInstance().append(txtOutput, "Execution is canceled.",
					StringConstant.ERROR, Printer.COLOR_ERROR);
			return false;
		}

		return true;
	}

	private void saveExecResult() {
		if (dataPkg == null) {
			return;
		}

		final NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return;
		}

		final ExecResultPkg execResultPkg = this.dataPkg
				.getNetworkExecResultPkg();
		if (ErrorChecker.getInstance().isNull(execResultPkg, txtOutput,
				"Execution Result")) {
			return;
		}

		final Network network = networkPkg.getNetwork();
		if (ErrorChecker.getInstance().isNull(network, txtOutput, "Network")
				|| ErrorChecker.getInstance().isEmpty(network.getNodeSet(),
						txtOutput, "Network")) {
			return;
		}

		final File file = openSaveFileDialog(execResultPkg.getTime() + "_"
				+ this.fileTitle);

		if (file == null) {
			return;
		}

		final FilePrinter p = new FilePrinter();
		final ProcessingMessageBox savingMessage = new ProcessingMessageBox(
				super.getDisplay().getActiveShell(), "Saving");

		SuccessThread thread = new SuccessThread("Saving Thread") {
			@Override
			public void run() {
				int i = 0;
				try {
					p.init(file);
					p.print("Network");
					ExecStatsFilePrinter.getInstance().print(p,
							execResultPkg.getExecStats());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					ExecResultFilePrinter.getInstance().print(p,
							execResultPkg.getExecResult());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					GraphStatsFilePrinter.getInstance().print(
							p,
							GraphStatsAnalyzer.getInstance().analyze("Network",
									GraphMaker.getInstance().make(network)));
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					NetworkStatsFilePrinter.getInstance().print(p,
							networkPkg.getNetworkStats());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					BGNetworkStatsFilePrinter.getInstance().print(p,
							networkPkg.getBgNetworkStats());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					p.close();

					isSuccess = true;
				} catch (Exception e) {
					e.printStackTrace();
					try {
						p.close();
					} catch (Exception ee) {
						ee.printStackTrace();
					}
					isSuccess = false;
				}

				savingMessage.close();
			}
		};
		savingMessage.setThread(thread);
		thread.start();

		if (thread.isAlive()) {
			savingMessage.open();
		}

		if (!thread.isSuccess()) {
			try {
				p.close();
				file.delete();
			} catch (Exception ee) {
				ee.printStackTrace();
			}
			Printer.getInstance().append(txtOutput, "Saving is canceled.",
					StringConstant.ERROR, Printer.COLOR_ERROR);
			return;
		}
	}

	private void saveFlowExecResult() {
		if (dataPkg == null) {
			return;
		}

		final NetworkPkg networkPkg = this.dataPkg.getNetworkPkg();
		if (ErrorChecker.getInstance().isNull(networkPkg, txtOutput, "Network")) {
			return;
		}

		final ExecResultPkg execResultPkg = this.dataPkg
				.getNetworkExecResultPkg();
		if (ErrorChecker.getInstance().isNull(execResultPkg, txtOutput,
				"Execution Result")) {
			return;
		}

		final String flowName = this.openChooseDialog(networkPkg.getNetwork()
				.getFlowMap().keySet(), "Flow");
		if (flowName == null) {
			return;
		}

		final Flow flow = networkPkg.getNetwork().getFlowMap().get(flowName);
		if (ErrorChecker.getInstance().isNull(flow, txtOutput, flowName)
				|| ErrorChecker.getInstance().isEmpty(flow.getNodeSet(),
						txtOutput, flowName)) {
			return;
		}

		final String title = "Flow " + flowName;

		final File file = openSaveFileDialog(execResultPkg.getTime() + "_"
				+ this.fileTitle + "_" + flowName);

		if (file == null) {
			return;
		}

		final FilePrinter p = new FilePrinter();
		final ProcessingMessageBox savingMessage = new ProcessingMessageBox(
				super.getDisplay().getActiveShell(), "Saving");

		SuccessThread thread = new SuccessThread("Saving Thread") {
			@Override
			public void run() {
				int i = 0;
				try {
					p.init(file);
					p.print(title);
					ExecStatsFilePrinter.getInstance().print(p,
							execResultPkg.getExecStats(), flow);
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					ExecResultFilePrinter.getInstance().print(p,
							execResultPkg.getExecResult(), flow);
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					GraphStatsFilePrinter.getInstance().print(
							p,
							GraphStatsAnalyzer.getInstance().analyze(title,
									GraphMaker.getInstance().make(flow)));
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					NetworkStatsFilePrinter.getInstance().print(p,
							networkPkg.getNetworkStats());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					BGNetworkStatsFilePrinter.getInstance().print(p,
							networkPkg.getBgNetworkStats());
					if (savingMessage.isAlive()) {
						i++;
						savingMessage.setProgress(i, 5);
					}
					p.close();

					isSuccess = true;
				} catch (Exception e) {
					e.printStackTrace();
					try {
						p.close();
					} catch (Exception ee) {
						ee.printStackTrace();
					}
					isSuccess = false;
				}

				savingMessage.close();
			}
		};
		savingMessage.setThread(thread);
		thread.start();

		if (thread.isAlive()) {
			savingMessage.open();
		}

		if (!thread.isSuccess()) {
			try {
				p.close();
				file.delete();
			} catch (Exception ee) {
				ee.printStackTrace();
			}
			Printer.getInstance().append(txtOutput, "Saving is canceled.",
					StringConstant.ERROR, Printer.COLOR_ERROR);
			return;
		}
	}

	private File openSaveFileDialog(String initFileName) {
		FileDialog dialog = new FileDialog(getDisplay().getActiveShell(),
				SWT.SAVE);
		try {
			dialog.setFilterPath(path);
		} catch (Exception e) {
			dialog.setFilterPath(System.getProperty("user.dir"));
		}
		dialog.setFileName(initFileName + ".txt");
		dialog.setFilterExtensions(new String[] { "*.txt" });
		File file;
		while (true) {
			String location = dialog.open();
			path = location;
			if (location == null) {
				Printer.getInstance().append(txtOutput, "Save is cancelled.",
						StringConstant.ERROR, Printer.COLOR_ERROR);
				return null;
			}
			file = new File(location);
			if (file.exists()) {
				MessageBox message = new MessageBox(getDisplay()
						.getActiveShell(), SWT.ICON_INFORMATION | SWT.YES
						| SWT.NO | SWT.CANCEL);
				message.setMessage("File exists, override?");
				switch (message.open()) {
				case SWT.YES:
					file.delete();
					break;
				case SWT.CANCEL:
					Printer.getInstance().append(txtOutput,
							"Save is cancelled.", StringConstant.WARNING,
							Printer.COLOR_WARNING);
					return null;
				default:
					continue;
				}
				break;
			} else {
				break;
			}
		}
		return file;
	}

	private String openChooseDialog(Collection<? extends String> optionList,
			String title) {
		ArrayList<String> list = new ArrayList<String>();
		for (String flow : optionList) {
			list.add(flow);
		}
		Collections.sort(list);
		ChooseDialog dlg = new ChooseDialog(getDisplay().getActiveShell(),
				title, list, new Point(600, 600));
		String flowName = dlg.open();
		if (flowName == null) {
			Printer.getInstance().append(txtOutput,
					"No " + title + " are selected.", StringConstant.WARNING,
					Printer.COLOR_WARNING);
			return null;
		}
		return flowName;
	}
}
